#ifndef _GRAPHICSLAYER_H
#define _GRAPHICSLAYER_H

#include "../StdAfx.h"
#include "../Application.h"
#include "../shaders/glsl.h"
#include "../../opengl/glm/glm.hpp"
#include "../../opengl/glm/gtc/matrix_transform.hpp"
#include <list>
#include <string>
using std::wstring;

#define MAX_LIGHTS 10	// Se debe asegurar que sea el mismo que en los shaders

#define DEFAULT_VELOCITY_Z 0.2 // La velocidad de desplazamiento en el eje z
#define DEFAULT_VELOCITY_X 0.2 // La velocidad de desplazamiento en el eje x

struct RotateModelDataSt{
    float x;
    float y;
    float z;
};

class cGraphicsLayer {
    int cWidth, cHeight;
    
    float cViewPort[4];
    float cFrustum[4];
    
    cwc::glShaderManager SM;
    cwc::glShader *cShader;
    
    GLuint c_ProgramObject;
    
    float EyePosition[3];
    float ViewPoint[3];
    float UpVector[3];
    
    bool automaticUpdate;
        
protected:
    cGraphicsLayer(); // Constructor
    static cGraphicsLayer* m_pGlobalGLayer; // Puntero al Objeto Global GFX

public:
    
    float colorClear[4];
    
    glm::mat4 matrixView;
    glm::mat4 matrixProjection;
    glm::mat4 matrixModel;
    glm::mat4 matrixMVP;

    // Shaders
    int inPositionTex;
    int MatrixPID;
    int MatrixMID;
    int MatrixVID;
    int MatrixMVPID;
            
    RotateModelDataSt RotateModelData;
    float ScaleModelData[3];
    float TranslateModelData[4];
    
    std::vector<std::string> m_pTexturesNamesList;
    std::vector<GLuint> m_pTexturesPointers;
    
    // Agrega luces a la array si hay espacio.
    void AddLight() {}

    // Manda la luces al shader
    void UpdateLights();

    GLuint LoadTexture(char* filename);
    GLuint LoadTextureFromGraphics(int id);
    void SetTexture(GLuint m_pTexture);
    void SetNumActiveTexture();

    void SendMatrix();
    
    // Envia las matrices de transformacion al shader
    void UpdateMatrices();

    void DestroyAll();
    ~cGraphicsLayer();

    /**
     * <summary> Inicializaciones. </summary>
     */
    void InitD3D();
    void UpdateFrustum(GLfloat fovy, GLfloat aspect, GLfloat zNear, GLfloat zFar);
    void CreateViewport();
    void CreateLookAt();
    
    void DisableFace();
    void SetDepth();
    
    void ScaleModel(float x, float y, float z);
    void TranslateModel(float x, float y, float z);

    void CheckOpenGLVersion();
    
    /**
     * <summary> Crea el Shader.
     *	Por defecto solo realiza la transformacion y devuelve el color de textura.</summary>
     */
    void CreateDefaultShader();
    void GetDefaultTextureInShader();
    void EnableDefaultShader();
    void DisableDefaultShader();
    
    void GetDefaultMatrixInShader();
    
    void EnableAutomaticUpdate();
    void DisableAutomaticUpdate();
    
    GLuint getProgramFromDefaultShader();
    
    /** 
     * <summary>Ancho de pantala</summary>
     */
    int Width() const {
        return cGraphicsLayer::cWidth;
    }

    /** 
     * <summary>Alto de pantala</summary>
     */
    int Height() const {
        return cGraphicsLayer::cHeight;
    }

    void SetColorClear(const float (&colClear)[4]);
    
    /** 
     * <summary>Limpia el back bugger</summary>
     * <param name="colClear">Color para pintar la pantalla</param>
     */
    void Clear();

    /** 
     * <summary>Puntero al Objeto GFX principal</summary>
     */
    static cGraphicsLayer* GetGraphics() {
        return m_pGlobalGLayer;
    }

    /** 
     * <summary>Inicializa el objeto</summary>
     */
    static void Create(); // guid del device
};

inline cGraphicsLayer* Graphics() {
    return cGraphicsLayer::GetGraphics();
}


#endif //_GRAPHICSLAYER_H